package io.modelcontextprotocol.autoconfigure.utils;

import io.modelcontextprotocol.autoconfigure.ToolCallback;
import io.modelcontextprotocol.autoconfigure.definition.DefaultToolCallResultConverter;
import io.modelcontextprotocol.autoconfigure.definition.Tool;
import io.modelcontextprotocol.autoconfigure.definition.ToolCallResultConverter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public final class ToolUtils {
    private ToolUtils() {
    }

    public static String getToolName(Method method) {
        Assert.notNull(method, "method cannot be null");
        Tool tool = (Tool)method.getAnnotation(Tool.class);
        if (tool == null) {
            return method.getName();
        } else {
            return StringUtils.hasText(tool.name()) ? tool.name() : method.getName();
        }
    }

    public static String getToolDescriptionFromName(String toolName) {
        Assert.hasText(toolName, "toolName cannot be null or empty");
        return ParsingUtils.reConcatenateCamelCase(toolName, " ");
    }

    public static String getToolDescription(Method method) {
        Assert.notNull(method, "method cannot be null");
        Tool tool = (Tool)method.getAnnotation(Tool.class);
        if (tool == null) {
            return ParsingUtils.reConcatenateCamelCase(method.getName(), " ");
        } else {
            return StringUtils.hasText(tool.description()) ? tool.description() : method.getName();
        }
    }

    public static boolean getToolReturnDirect(Method method) {
        Assert.notNull(method, "method cannot be null");
        Tool tool = (Tool)method.getAnnotation(Tool.class);
        return tool != null && tool.returnDirect();
    }

    public static ToolCallResultConverter getToolCallResultConverter(Method method) {
        Assert.notNull(method, "method cannot be null");
        Tool tool = (Tool)method.getAnnotation(Tool.class);
        if (tool == null) {
            return new DefaultToolCallResultConverter();
        } else {
            Class<? extends ToolCallResultConverter> type = tool.resultConverter();

            try {
                return (ToolCallResultConverter)type.getDeclaredConstructor().newInstance();
            } catch (Exception var4) {
                Exception e = var4;
                throw new IllegalArgumentException("Failed to instantiate ToolCallResultConverter: " + String.valueOf(type), e);
            }
        }
    }

    public static List<String> getDuplicateToolNames(List<ToolCallback> toolCallbacks) {
        Assert.notNull(toolCallbacks, "toolCallbacks cannot be null");
       Map<String,Long> toolNameCount= toolCallbacks.stream().collect(Collectors.groupingBy((toolCallback) -> {
            return toolCallback.getToolDefinition().name();
        }, Collectors.counting()));
        return toolNameCount.entrySet().stream().filter(entry->{
            return entry.getValue()>1L;
        }).map(Map.Entry::getKey).collect(Collectors.toList());
    }

    public static List<String> getDuplicateToolNames(ToolCallback... toolCallbacks) {
        Assert.notNull(toolCallbacks, "toolCallbacks cannot be null");
        return getDuplicateToolNames(Arrays.asList(toolCallbacks));
    }
}
